#!/usr/bin/python
# -*- coding: utf-8 -*-

from app.lib import BaseHandler
from igor import logging
import app.prop as prop 
from app.common import render
from app.common import gen_sign
from app.common import gen_bid
from app.common import md5 
from app.order import OrderManager
from app.order import OrderState
from app.dbutils import DBUtils 
from igor import urlfetch
import urllib
import datetime

class GenOrder(BaseHandler):
    """生成充值订单类。
    """
    
    def __init__(self):
        self.omanager = OrderManager()
        self.dbutils = DBUtils()

    def get(self, req, resp):  
        """接收商城的信息并创建订单,返回订单号。
        商城提交的信息字段：
        orderid：充值订单号。
        amount：充值金额
        moneytype：金额类型
        desc：描述信息
        mallid：商城在支付系统注册的id
        returnurl：商城跳转地址
        mode：加密方式
        expire：订单过期时间
        sign：以上信息加上商城密钥的md5签名。
        """
        orderid = req.args.get('orderid', [None])[0]
        amount = req.args.get('amount', [None])[0]
        moneytype = req.args.get('moneytype', [None])[0]
        desc = req.args.get('desc', [None])[0]
        mallid = req.args.get('mallid', [None])[0]
        returnurl = req.args.get('returnurl', [None])[0]
        mode = req.args.get('mode', [None])[0]
        expire = req.args.get('expire', [None])[0]
        sign = req.args.get('sign', [None])[0]
        logging.log('args=%s' % req.args)
        if not (orderid and amount and moneytype and desc and 
            mallid and mode and returnurl and expire and sign):
            logging.log('not all fields')
            return resp.respond('error') 
        try:
            amount = float('%.1f' % float(amount))
            moneytype = int(moneytype)
            expire = int(expire)
            if amount <= 0:
                return resp.respond('error') 
        except ValueError:
            logging.log('value format error')
            return resp.respond('error') 
        if mode != 'md5':
            logging.log('mode error')
            return resp.respond('error') 
        secret_key = prop.KEYS.get(mallid)
        sign_gen = gen_sign(orderid, amount, moneytype, desc, 
                returnurl, mallid, mode, expire, secret_key)
        if sign_gen != sign:
            logging.log('sign error')
            return resp.respond('error')
        bid, status = gen_bid(), 0
        ret = self.omanager.insert(bid, orderid, amount, moneytype, 
            mallid, expire, returnurl, status)
        if not ret:
            logging.log('bankorder insert error')
            return resp.respond('error')
        return resp.respond(bid)

    def post(self, req, resp):
        return self.get(req, resp)


class Bank(BaseHandler):
    """支付系统类，用于处理用户充值。
    """
    
    def __init__(self):
        self.omanager = OrderManager()
        self.dbutils = DBUtils()

    def get(self, req, resp):  
        bid = req.args.get('bid', [None])[0]
        order = self.omanager.query_by_bid(bid)
        if not order:
            return resp.respond('order not exist')
        expire = datetime.datetime.now() - datetime.timedelta(seconds=order.expire) 
        expire_time = expire.strftime("%Y-%m-%d %H:%M:%S")
        if str(order.bdate) < expire_time:
            return resp.respond('order expire')
        body = render('bank.html', {'order':order})
        return resp.respond(body)
        
    def post(self, req, resp):
        cardid = req.args.get('cardid', [None])[0]
        passwd = req.args.get('passwd', [None])[0]
        if not self.auth(cardid, passwd):
            return resp.respond('bad cardid or password')
        bid = req.args.get('bid', [None])[0]
        order = self.omanager.query_by_bid(bid)
        mall_cardid = prop.CARDS.get(order.mallid)
        ret = self.omanager.update(bid, cardid, mall_cardid)
        logging.log('pay result=%s' % ret)
        ##
        #支付成功的话，支付系统回调商城一次。
        ## 
        orderid, amount, moneytype, mallid = (order.orderid, order.amount,
            order.moneytype, order.mallid)
        status = ReturnStatus.PAYED 
        sign = gen_sign(orderid, amount, moneytype, 
            mallid, status, prop.KEYS.get(mallid))
        if ret == OrderState.SUCC:
            callbackurl = prop.URLS.get(mallid)  
            call(callbackurl, orderid=orderid, mallid=mallid, amount=amount, 
                moneytype=moneytype, status=status, sign=sign)
        patterns = {'order': order, 'sign':sign, 'status':status, 'ret':ret}
        body = render('bankok.html', patterns)
        return resp.respond(body)

    def auth(self, cardid, passwd):
        """验证支付账户。
        """
        sql = """
            SELECT passwd FROM user WHERE cardid=%s
        """
        rows = self.dbutils.execute_dict(sql, (cardid,))
        if rows:
            passwd_db = rows[0]['passwd']
            if md5(passwd) == passwd_db:
                return True
            else:
                return False
        else:
            return False


class ReturnStatus(object):
    """商城回调支付系统后支付系统返回的状态。
    """
    ARGS_ERR = '100'
    SIGN_ERR = '101'
    PAYED = '200'
    NOTPAYED = '201'
    NOTEXIST = '202'


class Callback(BaseHandler):
    """支付系统接收商城回调类。处理商城查询订单状态请求。
    """

    def __init__(self):
        self.omanager = OrderManager()

    def post(self, req, resp):
        """接收商城请求并返回订单状态。

        接收的接口参数：
        orderid：订单号，这是商城生成的订单号。
        mallid：商城在支付系统的标示，由此获取商城的密钥。
        sign： 签名，即商城使用密钥对orderid和mallid生成的签名。

        支付系统回调商城的参数：
        orderid: 订单号，还是商城订单号
        mallid：商城在支付系统的唯一标示
        amount：金额数目
        moneytype：金额类别
        status: 充值订单状态
        sign：以上字段加上商城密钥的md5签名

        充值订单状态代码：
        100：参数错误
        101：签名验证失败
        200：订单已经付款
        201：订单未付款
        202：订单不存在
        """
        orderid = req.args.get('orderid', [None])[0]
        mallid = req.args.get('mallid', [None])[0]
        sign = req.args.get('sign', [None])[0]
        if not (orderid and mallid and sign):
            status = ReturnStatus.ARGS_ERR 
        secret_key = prop.KEYS.get(mallid)
        callbackurl = prop.URLS.get(mallid)
        sign_gen = gen_sign(orderid, mallid, secret_key)
        if sign_gen != sign:
            status = ReturnStatus.SIGN_ERR 
        order = self.omanager.query(orderid, mallid)
        if not order:
            status = ReturnStatus.NOTEXIST 
            amount, moneytype = 1.0, 1
        else:
            amount, moneytype = order.amount, order.moneytype 
        if order.status == 1:
            status = ReturnStatus.PAYED 
        else:
            status = ReturnStatus.NOTPAYED 
        logging.log('moneytype=%s' % moneytype)
        sign = gen_sign(orderid, amount, moneytype, mallid, status, secret_key)
        call(callbackurl, orderid=orderid, mallid=mallid, amount=amount,
            moneytype=moneytype, status=status, sign=sign)
        return resp.respond()

    def get(self, req, resp):
        return self.post(req, resp)


def call(callbackurl, **args):
    """回调商城。
    """
    args = urllib.urlencode(args)
    fails = 1 
    while True: 
        if fails > 3:
            break
        logging.log('try %s times' % fails)
        try:
            urlfetch.fetch(callbackurl + '?' + args, 
                method='GET')
            break
        except Exception, err:
            fails += 1
            logging.log(err)
